package com.delos.rpc.aspect;

import com.delos.api.error.ExceptionEnum;
import com.delos.api.exception.ServiceException;
import com.delos.rpc.error.RpcException;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.rpc.RpcContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Pointcut;

/**
 * RPC接口统一异常处理
 *
 * @author zouyaowen
 * @date 2020-05-17
 */
@Slf4j
public class RpcExceptionAspect {

    /**
     * 定义切点
     */
    @Pointcut("@within(org.apache.dubbo.config.annotation.Service)")
    private void rpcPointcut() {
        // Do nothing just pointcut
    }

    @Around("rpcPointcut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();
        try {
            return pjp.proceed();
            // 业务自定义异常
        } catch (Exception e) {
            recordLog(pjp, args, e);
            RpcContext context = RpcContext.getContext();
            String remoteAddr = context.getRemoteAddressString();
            String localAddr = context.getLocalAddressString();
            String methodName = context.getMethodName();
            Object[] arguments = context.getArguments();
            if (e instanceof ServiceException) {
                ServiceException se = (ServiceException) e;
                throw new RpcException(se.getCode(), se.getMessage(), remoteAddr, localAddr, methodName, arguments);
            }
            throw new RpcException(ExceptionEnum.INTERNAL_ERROR.getCode(), ExceptionEnum.INTERNAL_ERROR.getMessage(), remoteAddr, localAddr, methodName, arguments);
        }
    }

    /**
     * 记录日志
     *
     * @param joinPoint 切点
     * @param args      参数
     * @param e         异常栈
     */
    private void recordLog(ProceedingJoinPoint joinPoint, Object[] args, Exception e) {
        StringBuilder sb = new StringBuilder();
        if (args != null && args.length > 0) {
            for (Object arg : args) {
                sb.append(",");
                sb.append(arg);
            }
        }
        log.error("方法: [{}]", joinPoint.toLongString());
        log.error("入参: [{}]", sb.toString());
        log.error("RPC异常信息栈", e);
    }
}
